package com.ibeeking.found.cop.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.utils.DateUtils;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.cop.b.rest.service.IGroupFriendsService;
import com.ibeeking.found.cop.b.rest.service.IGroupService;
import com.ibeeking.found.cop.b.rest.service.IMqService;
import com.ibeeking.found.cop.service.common.dos.*;
import com.ibeeking.found.cop.service.common.enums.MqSyncOperatorTypeEnum;
import com.ibeeking.found.cop.service.common.param.GroupAdminsParam;
import com.ibeeking.found.cop.service.common.param.GroupFriendsParam;
import com.ibeeking.found.cop.service.common.param.GroupParam;
import com.ibeeking.found.cop.service.common.param.MqSyncCopParam;
import com.ibeeking.found.cop.service.common.po.GroupTagsRelPO;
import com.ibeeking.found.cop.service.common.query.GroupPageQuery;
import com.ibeeking.found.cop.service.common.query.GroupQuery;
import com.ibeeking.found.cop.service.common.vo.GroupFriendsVO;
import com.ibeeking.found.cop.service.common.vo.GroupVO;
import com.ibeeking.found.cop.service.mapper.*;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName GroupServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-01-27 18:50
 **/
@Service
public class GroupServiceImpl  extends ServiceImpl<GroupMapper, GroupDO> implements IGroupService {

    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Resource
    private GroupMapper groupMapper;

    @Resource
    private GroupAdminsMapper groupAdminsMapper;

    @Resource
    private GroupTagsRelMapper groupTagsRelMapper;

    @Resource
    private CopEmployeeMapper copEmployeeMapper;

    @Resource
    private FriendsMapper friendsMapper;

    @Resource
    private IGroupFriendsService groupFriendsServiceImpl;

    @Resource
    private IMqService mqServiceImpl;

    @Override
    public List<GroupVO> list(GroupQuery query) {
        String tenantId = UserUtils.getTenantId();
        List<Long> groupIds = new ArrayList<>();
        List<GroupVO> entityVOS = new ArrayList<>();
        Set<Long> tagIds = query.getTagsIds();
        if(tagIds!=null && tagIds.size() >0){
            List<GroupTagsRelDO> friendsTagsRelDOS = groupTagsRelMapper.listByTagsIds(Integer.valueOf(tenantId), tagIds);
            if(Collections3.isNotEmpty(friendsTagsRelDOS)) {
                groupIds = friendsTagsRelDOS.stream().map(GroupTagsRelDO::getGroupId).collect(Collectors.toList());
            }else{
                groupIds.add(-1L);
            }
        }

        List<GroupDO> entityDOS = groupMapper.selectList(new LambdaQueryWrapper<GroupDO>()
                .eq(query.getId() != null, GroupDO::getId, query.getId())
                .eq(StringUtils.isNotBlank(query.getChatId()), GroupDO::getChatId, query.getChatId())
                .eq(StringUtils.isNotBlank(query.getOwnerCode()), GroupDO::getOwnerCode, query.getOwnerCode())
                .eq(query.getOwnerId() != null, GroupDO::getOwnerId, query.getOwnerId())
                .eq(StringUtils.isNotBlank(query.getOwnerCode()), GroupDO::getOwnerCode, query.getOwnerCode())
                .like(StringUtils.isNotBlank(query.getName()), GroupDO::getName, query.getName())
                .in(Collections3.isNotEmpty(groupIds), GroupDO::getId, groupIds)
                .eq(query.getStatus() != null, GroupDO::getStatus, query.getStatus())
                .ge(StringUtils.isNotBlank(query.getBuildTimeBegin()), GroupDO::getBuildTime, query.getBuildTimeBegin())
                .le(StringUtils.isNotBlank(query.getBuildTimeEnd()), GroupDO::getBuildTime, query.getBuildTimeEnd())
                .orderByDesc(GroupDO::getCreateTime)
        );
        if(Collections3.isNotEmpty(entityDOS)) {
            List<CopEmployeeDO> copEmployeeDOS = copEmployeeMapper.selectList(new LambdaQueryWrapper<>());
            Map<Long, String> copEmployeeNameMaps =copEmployeeDOS.stream().collect(Collectors.toMap(CopEmployeeDO::getId, CopEmployeeDO::getEmployeeName, (o, n) -> n));

            entityVOS = JsonUtils.jsonToList(entityDOS, GroupVO.class);
            entityVOS.forEach(x -> {
                Long groupId = x.getId();
                List<GroupTagsRelPO> groupTagsRelPOS =  groupTagsRelMapper.listTagsByGroupId(Integer.valueOf(tenantId), groupId);
                if(groupTagsRelPOS!=null && groupTagsRelPOS.size()>0) {
                    List<String> groupTagsList = groupTagsRelPOS.stream().map(GroupTagsRelPO::getTagsName).collect(Collectors.toList());
                    String groupTagsStr = StringUtils.join(groupTagsList, ",");
                    x.setGroupTagsStr(groupTagsStr);
                    x.setGroupTagsRel(groupTagsRelPOS);
                }
                List<GroupFriendsVO> groupFriendsVOS= groupFriendsServiceImpl.listByGroupId(groupId);

                if(Collections3.isNotEmpty(groupFriendsVOS)){
                    x.setSumGroupFriendsNum(groupFriendsVOS.size());
                    Integer todayJoinNum = 0;
                    Integer todayOutNum = 0;
                    for(GroupFriendsVO d: groupFriendsVOS){
                        String joinTime = d.getFriendsJoinTime();
                        String outTime = d.getFriendsOutTime();
                        if( StringUtils.isNotEmpty(joinTime) && DateUtils.isToday(joinTime)) {
                            todayJoinNum = todayJoinNum + 1;
                        }
                        if(StringUtils.isNotEmpty(outTime) && DateUtils.isToday(outTime)){
                            todayOutNum = todayOutNum +1;
                        }
                    }
                    x.setTodayJoinNum(todayJoinNum);
                    x.setTodayOutNum(todayOutNum);
                }else{
                    x.setSumGroupFriendsNum(0);
                    x.setTodayJoinNum(0);
                    x.setTodayOutNum(0);
                }
                x.setOwnerName(x.getOwnerId() !=null?copEmployeeNameMaps.get(x.getOwnerId()):"");
                x.setStatusDesc(PublishStatusEnum.getName(x.getStatus()));
            });
        }
        LogUtils.info("========entityVOS:{}==========",JsonUtils.toJsonStr(entityVOS));
        return entityVOS;
    }

    @Override
    public Page<GroupVO> pageList(GroupPageQuery pageQuery) {
        String tenantId = UserUtils.getTenantId();
        List<Long> groupIds = new ArrayList<>();
        List<GroupVO> entityVOS = new ArrayList<>();
        Set<Long> tagIds = pageQuery.getTagsIds();
        if(tagIds!=null && tagIds.size() >0){
            List<GroupTagsRelDO> friendsTagsRelDOS = groupTagsRelMapper.listByTagsIds(Integer.valueOf(tenantId), tagIds);
            if(Collections3.isNotEmpty(friendsTagsRelDOS)) {
                groupIds = friendsTagsRelDOS.stream().map(GroupTagsRelDO::getGroupId).collect(Collectors.toList());
            }else{
                groupIds.add(-1L);
            }
        }

        LambdaQueryWrapper<GroupDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(pageQuery.getId() != null, GroupDO::getId, pageQuery.getId())
                .eq(StringUtils.isNotBlank(pageQuery.getChatId()), GroupDO::getChatId, pageQuery.getChatId())
                .in(Collections3.isNotEmpty(groupIds), GroupDO::getId, groupIds)
                .eq(pageQuery.getStatus() != null, GroupDO::getStatus, pageQuery.getStatus())
                .eq(pageQuery.getOwnerId() != null, GroupDO::getOwnerId, pageQuery.getOwnerId())
                .like(StringUtils.isNotBlank(pageQuery.getName()), GroupDO::getName, pageQuery.getName())
                .eq(StringUtils.isNotBlank(pageQuery.getOwnerCode()), GroupDO::getOwnerCode, pageQuery.getOwnerCode())
                .ge(StringUtils.isNotBlank(pageQuery.getBuildTimeBegin()), GroupDO::getBuildTime, pageQuery.getBuildTimeBegin())
                .le(StringUtils.isNotBlank(pageQuery.getBuildTimeEnd()), GroupDO::getBuildTime, pageQuery.getBuildTimeEnd())
                .orderByDesc(GroupDO::getCreateTime);
        Page<GroupDO> entityDOPages = groupMapper.selectPage(new Page<GroupDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);

        Page<GroupVO> entityVOPages = BeanUtil.convertPage(entityDOPages, GroupVO.class);

        if(entityVOPages!= null && entityVOPages.getSize() >0 ) {
            List<CopEmployeeDO> copEmployeeDOS = copEmployeeMapper.selectList(new LambdaQueryWrapper<CopEmployeeDO>());
            Map<Long, String> copEmployeeNameMaps =copEmployeeDOS.stream().collect(Collectors.toMap(CopEmployeeDO::getId, CopEmployeeDO::getEmployeeName, (o, n) -> n));
            LogUtils.info("====copEmployeeNameMaps:{}====" ,JsonUtils.toJsonStr(copEmployeeNameMaps));

            entityVOPages.getRecords().forEach(f -> {
                Long groupId = f.getId();
                List<GroupTagsRelPO> groupTagsRelPOS =  groupTagsRelMapper.listTagsByGroupId(Integer.valueOf(tenantId), groupId);
                if(groupTagsRelPOS!=null && groupTagsRelPOS.size()>0) {
                    List<String> groupTagsList = groupTagsRelPOS.stream().map(GroupTagsRelPO::getTagsName).collect(Collectors.toList());
                    String groupTagsStr = StringUtils.join(groupTagsList, ",");
                    f.setGroupTagsStr(groupTagsStr);
                    f.setGroupTagsRel(groupTagsRelPOS);
                }
                List<GroupFriendsVO> groupFriendsVOS= groupFriendsServiceImpl.listByGroupId(groupId);

                if(Collections3.isNotEmpty(groupFriendsVOS)){
                    f.setSumGroupFriendsNum(groupFriendsVOS.size());
                    Integer todayJoinNum = 0;
                    Integer todayOutNum = 0;
                    for(GroupFriendsVO d: groupFriendsVOS){
                        String joinTime = d.getFriendsJoinTime();
                        String outTime = d.getFriendsOutTime();
                        if(StringUtils.isNotEmpty(joinTime) && DateUtils.isToday(joinTime)) {
                            todayJoinNum = todayJoinNum + 1;
                        }
                        if(StringUtils.isNotEmpty(outTime) && DateUtils.isToday(outTime)){
                            todayOutNum = todayOutNum +1;
                        }
                    }
                    f.setTodayJoinNum(todayJoinNum);
                    f.setTodayOutNum(todayOutNum);
                }else{
                    f.setSumGroupFriendsNum(0);
                    f.setTodayJoinNum(0);
                    f.setTodayOutNum(0);
                }
                f.setOwnerName(f.getOwnerId() != null?copEmployeeNameMaps.get(f.getOwnerId()):"");
                f.setStatusDesc(PublishStatusEnum.getName(f.getStatus()));
            });
        }
        return entityVOPages;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(GroupParam param) {
        checkUnique(param);
        GroupDO entityDO = BeanUtil.convertBean(param, GroupDO.class);
        entityDO.setId(GenerateId.generateId());
        entityDO.setCreateBy(UserUtils.getUserId());
        entityDO.setCreateTime(LocalDateTime.now());
        entityDO.setModifyTime(LocalDateTime.now());
        return groupMapper.insert(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean modify(GroupParam param) {
        GroupDO entityDO = BeanUtil.convertBean(param, GroupDO.class);
        entityDO.setModifyBy(UserUtils.getUserId());
        entityDO.setModifyTime(LocalDateTime.now());
        return groupMapper.updateById(entityDO) > 0;
    }

    @Override
    public GroupVO view(Long id) {
        String tenantId = UserUtils.getTenantId();
        GroupDO entityDO = groupMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        GroupVO entityVO = BeanUtil.convertBean(entityDO, GroupVO.class);
        if(entityVO != null) {
            List<CopEmployeeDO> copEmployeeDOS = copEmployeeMapper.selectList(new LambdaQueryWrapper<>());
            Map<Long, String> copEmployeeNameMaps =copEmployeeDOS.stream().collect(Collectors.toMap(CopEmployeeDO::getId, CopEmployeeDO::getEmployeeName, (o, n) -> n));

            entityVO.setOwnerName(entityVO.getOwnerId()!=null?copEmployeeNameMaps.get(entityVO.getOwnerId()):"");
            List<GroupTagsRelPO> groupTagsRelPOS =  groupTagsRelMapper.listTagsByGroupId(Integer.valueOf(tenantId), id);
            if(groupTagsRelPOS!=null && groupTagsRelPOS.size()>0) {
                List<String> groupTagsList = groupTagsRelPOS.stream().map(GroupTagsRelPO::getTagsName).collect(Collectors.toList());
                String groupTagsStr = StringUtils.join(groupTagsList, ",");
                entityVO.setGroupTagsStr(groupTagsStr);
                entityVO.setGroupTagsRel(groupTagsRelPOS);
            }
            List<GroupFriendsVO> groupFriendsVOS= groupFriendsServiceImpl.listByGroupId(id);

            if(Collections3.isNotEmpty(groupFriendsVOS)){
                entityVO.setSumGroupFriendsNum(groupFriendsVOS.size());
                Integer todayJoinNum = 0;
                Integer todayOutNum = 0;
                for(GroupFriendsVO d: groupFriendsVOS){
                    String joinTime = d.getFriendsJoinTime();
                    String outTime = d.getFriendsOutTime();
                    if(StringUtils.isNotEmpty(joinTime) && DateUtils.isToday(joinTime)) {
                        todayJoinNum = todayJoinNum + 1;
                    }
                    if(StringUtils.isNotEmpty(outTime) && DateUtils.isToday(outTime)){
                        todayOutNum = todayOutNum +1;
                    }
                }
                entityVO.setTodayJoinNum(todayJoinNum);
                entityVO.setTodayOutNum(todayOutNum);
            }else{
                entityVO.setSumGroupFriendsNum(0);
                entityVO.setTodayJoinNum(0);
                entityVO.setTodayOutNum(0);
            }
            entityVO.setBuildTime(dateTimeFormatter.format(entityDO.getBuildTime()));
            entityVO.setStatusDesc(PublishStatusEnum.getName(entityDO.getStatus()));
        }
        return entityVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeStatus(Long id, Integer status) {
        GroupDO entityDO = groupMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        entityDO.setStatus(status);
        entityDO.setModifyBy(UserUtils.getUserId());
        entityDO.setModifyTime(LocalDateTime.now());
        return groupMapper.updateById(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean del(Long id) {
        GroupDO entityDO = groupMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        return groupMapper.deleteById(id) > 0;
    }
    /**
     * 从企业微信同步q群信息
     *
     * @param
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer syncGroupFromWx(){
        String tenantId = UserUtils.getTenantId();
        MqSyncCopParam mqParam = new MqSyncCopParam();
        mqParam.setTenantId(Long.valueOf(tenantId));
        mqParam.setOperType(MqSyncOperatorTypeEnum.COP_SYNC_GROUPS_LIST.getCode());
        mqServiceImpl.sendSyncToWxTaskMessage(mqParam);
        return 1;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveOrUpdateOrDeleteBatchGroups(Long tenantId, List<GroupParam> params){
        if(Collections3.isNotEmpty(params)) {
            List<Long> groupIds = new ArrayList<>();
            List<GroupDO> needInsertGroupDOS = new ArrayList<>();
            List<GroupDO> needUpdateGroupDOS = new ArrayList<>();
            List<GroupDO> needDeleteGroupDOS = new ArrayList<>();
            Map<String, Long> groupChatIdAndIdMap = null;
            List<String> allFriendsCodes = new ArrayList<>();
            List<GroupDO> oldGroupDOS = groupMapper.selectList(new LambdaQueryWrapper<GroupDO>());
            if(Collections3.isNotEmpty(oldGroupDOS)) {
                groupChatIdAndIdMap = oldGroupDOS.parallelStream().collect(Collectors.toMap(GroupDO::getChatId, GroupDO::getId, (o, n) -> o));
                List<String> oldGroupChatIdList = oldGroupDOS.parallelStream().map(GroupDO::getChatId).collect(Collectors.toList());
                List<String> newGroupChatIdList = params.parallelStream().map(GroupParam::getChatId).collect(Collectors.toList());
                if (Collections3.isNotEmpty(oldGroupChatIdList) && Collections3.isNotEmpty(newGroupChatIdList)) {
                    HashSet<String> oldGroupChatIdHash = new HashSet<>(oldGroupChatIdList);
                    HashSet<String> newGroupChatIdHash = new HashSet<>(newGroupChatIdList);
                    oldGroupChatIdHash.removeAll(newGroupChatIdHash);
                    if (oldGroupChatIdHash.size() > 0) {
                        List<String> needDeleteGroupChatIds = new ArrayList<>(oldGroupChatIdHash);
                        needDeleteGroupDOS = groupMapper.selectList(new LambdaQueryWrapper<GroupDO>().in(GroupDO::getChatId, needDeleteGroupChatIds));
                    }
                }
            }
            List<CopEmployeeDO> employeeDOS = copEmployeeMapper.selectList(new LambdaQueryWrapper<>());
            Map<String, Long> employeeCodeMaps =employeeDOS.stream().collect(Collectors.toMap(CopEmployeeDO::getEmployeeCode, CopEmployeeDO::getId, (o, n) -> n));
            List<GroupAdminsDO> groupAdminsDOS = new ArrayList<>();
            Map<Long, List<GroupFriendsDO>> groupFriendsDOSMap = new HashMap<>();
            List<GroupFriendsDO> groupFriendsDOSList = new ArrayList<>();
            for(GroupParam d:params){
                GroupDO groupDO = BeanUtil.convertBean(d, GroupDO.class);
                Long groupId = 0L;

                groupDO.setCreateTime(LocalDateTime.now());
                groupDO.setModifyTime(LocalDateTime.now());
                groupDO.setChatId(d.getChatId());
                groupDO.setName(d.getName());
                groupDO.setNotice(d.getNotice());
                if (StringUtils.isNotEmpty(d.getOwnerCode())){
                    groupDO.setOwnerId(employeeCodeMaps.get(d.getOwnerCode()));
                }
                if(StringUtils.isNotEmpty(d.getBuildTime())) {
                    groupDO.setBuildTime(DateUtils.strToLocalDateTime(d.getBuildTime()));
                }
                if(groupChatIdAndIdMap!=null && groupChatIdAndIdMap.containsKey(d.getChatId())){
                    groupId = groupChatIdAndIdMap.get(d.getChatId());
                    groupDO.setId(groupId);
                    needUpdateGroupDOS.add(groupDO);
                    groupIds.add(groupId);
                }else{
                    groupId = IdGenerator.getId();
                    groupDO.setId(groupId);
                    needInsertGroupDOS.add(groupDO);
                    groupIds.add(groupId);
                }
                List<GroupAdminsParam> groupAdminsParamList = d.getGroupAdminsList();
                if(Collections3.isNotEmpty(groupAdminsParamList)){
                    for(GroupAdminsParam f: groupAdminsParamList){
                        GroupAdminsDO groupAdminsDO = new GroupAdminsDO();
                        groupAdminsDO.setId(IdGenerator.getId());
                        groupAdminsDO.setGroupId(groupId);
                        groupAdminsDO.setChatId(d.getChatId());
                        groupAdminsDO.setEmployeeCode(f.getEmployeeCode());
                        groupAdminsDO.setEmployeeId(employeeCodeMaps.get(f.getEmployeeCode()));
                        groupAdminsDOS.add(groupAdminsDO);
                    }
                }
                List<GroupFriendsParam>  groupFriendsParamList = d.getGroupFriendsList();
                if(Collections3.isNotEmpty(groupFriendsParamList)) {
                    for (GroupFriendsParam g: groupFriendsParamList) {
                        GroupFriendsDO groupFriendsDO = BeanUtil.convertBean(g, GroupFriendsDO.class);
                        allFriendsCodes.add(g.getFriendsCode());
                        groupFriendsDO.setId(IdGenerator.getId());
                        groupFriendsDO.setGroupId(groupId);
                        if(StringUtils.isNotEmpty(g.getFriendsJoinTime())) {
                            groupFriendsDO.setFriendsJoinTime(DateUtils.strToLocalDateTime(g.getFriendsJoinTime()));
                        }
                        if(StringUtils.isNotEmpty(g.getInvitorCode())) {
                            groupFriendsDO.setInvitorId(employeeCodeMaps.get(g.getInvitorCode()));
                        }
                        groupFriendsDOSList.add(groupFriendsDO);
                    }
                    groupFriendsDOSMap.put(groupId, groupFriendsDOSList);
                }
            }
            if(Collections3.isNotEmpty(needDeleteGroupDOS)){
                List<Long> delIds = needDeleteGroupDOS.stream().map(GroupDO::getId).collect(Collectors.toList());
                groupMapper.deleteBatchIds(delIds);
            }

            if(Collections3.isNotEmpty(needInsertGroupDOS)){
                groupMapper.insertBatchSomeColumn(needInsertGroupDOS);
            }
            if(Collections3.isNotEmpty(needUpdateGroupDOS)){
                super.updateBatchById(needUpdateGroupDOS);
            }
            if(Collections3.isNotEmpty(groupAdminsDOS)){
                groupAdminsMapper.deleteByGroupId(tenantId, new HashSet<>(groupIds));
                groupAdminsMapper.insertBatchSomeColumn(groupAdminsDOS);
            }
            if(groupFriendsDOSMap!=null && groupFriendsDOSMap.size()>0){
                groupFriendsServiceImpl.saveOrUpdateOrDeleteBatchGroupFriends(tenantId, groupFriendsDOSMap, allFriendsCodes);
            }
        }
        return 1;
    }
    /**
     * 校验唯一性
     *
     * @param param
     */
    public void checkUnique(GroupParam param) {
        if (param == null) {
            throw new BusinessException("当前记录不存在!");
        }
        //code name确保等级唯一性
        LambdaQueryWrapper<GroupDO> queryWrapper = new LambdaQueryWrapper<GroupDO>()
                .ne(param.getId() != null, GroupDO::getId, param.getId())
                .eq(GroupDO::getName, param.getName());
        List<GroupDO> dos = groupMapper.selectList(queryWrapper);
        if (Collections3.isNotEmpty(dos)) {
            throw new BusinessException("已经存在同名的记录!");
        }
    }

}
